package core

import (
	"fmt"
	"reflect"
	"strings"

	"jlpay-sdk-go/pkg/jlpay/utils"
)

// RawMapGetter 原始请求映射获取接口
type RawMapGetter interface {
	// GetRawMap 获取原始请求映射数据
	GetRawMap() (map[string]interface{}, bool)
}

// SensitiveFieldsGetter 敏感字段获取器接口
type SensitiveFieldsGetter interface {
	// GetSensitiveFields 获取敏感字段列表
	GetSensitiveFields() []string
}

// CryptoService 加密服务接口
type CryptoService interface {
	// EncryptRequest 加密请求
	EncryptRequest(request interface{}) (map[string]string, error)

	// DecryptResponse 解密响应
	DecryptResponse(response interface{}, headers map[string]string) error
}

// DefaultCryptoService 默认加密服务实现
type DefaultCryptoService struct {
	config *Config
}

// NewDefaultCryptoService 创建默认加密服务
func NewDefaultCryptoService(config *Config) *DefaultCryptoService {
	return &DefaultCryptoService{
		config: config,
	}
}

// EncryptRequest 加密请求
func (s *DefaultCryptoService) EncryptRequest(request interface{}) (map[string]string, error) {
	headers := make(map[string]string)

	// 1. 检查是否需要加密
	if !s.config.AutoEncrypt {
		// 即使未启用加密，仍然添加加密算法头，确保服务端识别请求类型
		headers["x-jlpay-crypto-alg"] = "SM2WithSM4"
		utils.Debugf("自动加密未启用，仅添加加密算法头")
		return headers, nil
	}

	// 检查加密算法是否支持
	if s.config.CryptoAlg != "SM2WithSM4" {
		return headers, fmt.Errorf("不支持的加密算法: %s", s.config.CryptoAlg)
	}

	// 2. 获取敏感字段
	sensitiveFields := s.getSensitiveFields(request)
	if len(sensitiveFields) == 0 {
		headers["x-jlpay-crypto-alg"] = "SM2WithSM4"
		utils.Debugf("未配置敏感字段，仅添加加密算法头")
		return headers, nil
	}

	// 3. 生成并加密SM4密钥
	sm4Key, encryptedKeyBase64, err := s.generateAndEncryptKey()
	if err != nil {
		return nil, err
	}

	// 4. 设置基本加密头
	headers["x-jlpay-crypto-alg"] = "SM2WithSM4"
	headers["x-jlpay-key"] = encryptedKeyBase64

	// 5. 加密敏感字段
	err = s.encryptSensitiveFieldsInRequest(request, sensitiveFields, sm4Key)
	if err != nil {
		return nil, fmt.Errorf("加密敏感字段失败: %w", err)
	}

	return headers, nil
}

// getSensitiveFields 获取敏感字段列表
func (s *DefaultCryptoService) getSensitiveFields(request interface{}) []string {
	var sensitiveFields []string
	if getter, ok := request.(interface{ GetSensitiveFields() []string }); ok {
		sensitiveFields = getter.GetSensitiveFields()
		utils.Debugf("获取到敏感字段: %v", sensitiveFields)
	} else {
		utils.Debugf("请求对象未实现GetSensitiveFields接口")
	}
	return sensitiveFields
}

// generateAndEncryptKey 生成SM4密钥并使用SM2加密
func (s *DefaultCryptoService) generateAndEncryptKey() ([]byte, string, error) {
	// 生成SM4密钥
	sm4Key, err := utils.GenerateSM4Key()
	if err != nil {
		return nil, "", fmt.Errorf("生成SM4密钥失败: %w", err)
	}
	utils.Debugf("成功生成SM4密钥")

	// 使用SM2加密SM4密钥
	encryptedKey, err := utils.SM2Encrypt(sm4Key, s.config.JlpayPublicKey)
	if err != nil {
		return nil, "", fmt.Errorf("SM2加密SM4密钥失败: %w", err)
	}
	utils.Debugf("成功使用SM2加密SM4密钥")

	// 将加密后的密钥转为Base64字符串
	encryptedKeyBase64 := utils.ToBase64String(encryptedKey)

	return sm4Key, encryptedKeyBase64, nil
}

// encryptSensitiveFieldsInRequest 加密请求中的敏感字段
func (s *DefaultCryptoService) encryptSensitiveFieldsInRequest(request interface{}, sensitiveFields []string, sm4Key []byte) error {
	rawMapGetter, ok := request.(RawMapGetter)
	if !ok {
		utils.Debugf("请求对象未实现RawMapGetter接口，无法修改原始请求")
		return fmt.Errorf("请求对象未实现RawMapGetter接口")
	}

	rawMap, exist := rawMapGetter.GetRawMap()
	if !exist || len(rawMap) == 0 {
		utils.Debugf("原始请求Map为空或不存在")
		return fmt.Errorf("原始请求Map为空或不存在")
	}

	utils.Debugf("使用原始Map方式处理敏感字段")
	return s.encryptFieldsInMap(rawMap, sensitiveFields, sm4Key)
}

// encryptFieldsInMap 加密Map中的敏感字段
func (s *DefaultCryptoService) encryptFieldsInMap(data map[string]interface{}, sensitiveFields []string, sm4Key []byte) error {
	modified := false

	for _, fieldPath := range sensitiveFields {
		err := s.encryptFieldInMap(data, fieldPath, sm4Key)
		if err != nil {
			// 记录错误但继续处理其他字段
			utils.Debugf("字段 %s 加密失败: %v", fieldPath, err)
		} else {
			modified = true
		}
	}

	if modified {
		utils.Debugf("成功更新原始请求Map中的敏感字段")
	} else {
		utils.Debugf("未对原始请求Map进行任何更新")
	}

	return nil
}

// encryptFieldInMap 加密Map中的单个敏感字段
func (s *DefaultCryptoService) encryptFieldInMap(data map[string]interface{}, fieldPath string, sm4Key []byte) error {
	utils.Debugf("=== 开始加密字段: %s ===", fieldPath)
	utils.Debugf("原始数据顶级键: %v", getMapKeys(data))

	// 1. 获取字段值
	value, err := getNestedMapValue(data, fieldPath)
	if err != nil {
		utils.Debugf("警告: 字段 %s 不存在或不可访问: %v", fieldPath, err)
		// 检查字段路径是否部分存在
		if !pathExists(data, fieldPath) {
			utils.Debugf("字段路径 %s 完全不存在，跳过加密", fieldPath)
			return fmt.Errorf("字段路径 %s 不存在", fieldPath)
		}
		return fmt.Errorf("字段 %s 访问失败: %w", fieldPath, err)
	}

	// 2. 检查并加密字段值
	strValue, ok := value.(string)
	if !ok || strValue == "" {
		utils.Debugf("字段 %s 的值不是字符串或为空，跳过加密", fieldPath)
		return fmt.Errorf("字段 %s 不是字符串或为空", fieldPath)
	}

	// 3. 加密字段值
	encryptedValue, err := s.encryptFieldValue(strValue, sm4Key)
	if err != nil {
		utils.Debugf("加密字段 %s 失败: %v", fieldPath, err)
		return fmt.Errorf("加密字段 %s 的值失败: %w", fieldPath, err)
	}

	// 4. 设置加密后的值
	err = setNestedMapValue(data, fieldPath, encryptedValue)
	if err != nil {
		utils.Debugf("更新字段 %s 的加密值失败: %v", fieldPath, err)
		return fmt.Errorf("更新字段 %s 的加密值失败: %w", fieldPath, err)
	}

	utils.Debugf("成功加密并更新字段 %s", fieldPath)
	return nil
}

// pathExists 检查字段路径是否部分存在于map中
func pathExists(data map[string]interface{}, path string) bool {
	parts := strings.Split(path, ".")
	var current interface{} = data

	// 检查每个路径部分是否存在
	for i, part := range parts {
		// 尝试转换为map[string]interface{}
		if currentMapInterface, ok := current.(map[string]interface{}); ok {
			next, exists := currentMapInterface[part]
			if !exists {
				utils.Debugf("路径检查失败: %s 中的 %s 不存在于map[string]interface{}中", path, part)
				return false
			}

			// 最后一个部分，路径存在
			if i == len(parts)-1 {
				return true
			}

			// 继续检查下一级
			current = next
			continue
		}

		// 尝试转换为map[string]string
		if currentMapString, ok := current.(map[string]string); ok {
			_, exists := currentMapString[part]
			if !exists {
				utils.Debugf("路径检查失败: %s 中的 %s 不存在于map[string]string中", path, part)
				return false
			}

			// 最后一个部分，路径存在
			if i == len(parts)-1 {
				return true
			}

			// map[string]string不能再向下遍历，路径无效
			utils.Debugf("路径检查失败: %s 中的 %s 处是map[string]string，无法继续向下", path, part)
			return false
		}

		// 都不是map类型
		utils.Debugf("路径检查失败: %s 中的 %s 处，当前值不是map，类型为: %T", path, part, current)
		return false
	}

	return true
}

// getMapKeys 获取map的所有键，用于调试
func getMapKeys(m map[string]interface{}) []string {
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	return keys
}

// setNestedMapValue 设置嵌套map中的字段值，如果路径不存在则创建
func setNestedMapValue(data map[string]interface{}, path string, value string) error {
	parts := strings.Split(path, ".")

	// 当前处理层级的map
	var current interface{} = data

	utils.Debugf("设置嵌套值: %s = %s", path, value)

	// 遍历路径中的每个部分，创建路径并设置值
	for i, part := range parts {
		// 最后一个部分，直接设置值
		if i == len(parts)-1 {
			// 尝试设置到map[string]interface{}
			if currentMapInterface, ok := current.(map[string]interface{}); ok {
				currentMapInterface[part] = value
				utils.Debugf("成功设置到map[string]interface{}: %s = %s", part, value)
				return nil
			}

			// 尝试设置到map[string]string
			if currentMapString, ok := current.(map[string]string); ok {
				currentMapString[part] = value
				utils.Debugf("成功设置到map[string]string: %s = %s", part, value)
				return nil
			}

			return fmt.Errorf("无法设置字段 %s，当前容器类型为: %T", part, current)
		}

		// 不是最后一部分，检查下一级是否存在，不存在则创建
		// 尝试处理map[string]interface{}
		if currentMapInterface, ok := current.(map[string]interface{}); ok {
			next, exists := currentMapInterface[part]
			if !exists {
				// 创建新map并设置到当前层级
				newMap := make(map[string]interface{})
				currentMapInterface[part] = newMap
				current = newMap
				continue
			}

			// 下一级存在，确保是map类型
			if nextMapInterface, ok := next.(map[string]interface{}); ok {
				// 下一级是map[string]interface{}，继续处理
				current = nextMapInterface
				continue
			}

			if nextMapString, ok := next.(map[string]string); ok {
				// 下一级是map[string]string，继续处理
				current = nextMapString
				continue
			}

			// 已存在但不是map，将其替换为map[string]interface{}
			utils.Debugf("替换非map节点 %s 为map[string]interface{}", part)
			newMap := make(map[string]interface{})
			currentMapInterface[part] = newMap
			current = newMap
			continue
		}

		// 当前是map[string]string
		if _, ok := current.(map[string]string); ok {
			// map[string]string无法创建下级map，需要替换为map[string]interface{}
			// 但这里需要往上追溯到父级map来替换
			return fmt.Errorf("无法在map[string]string中创建下级路径: %s", strings.Join(parts[:i+1], "."))
		}

		// 当前不是map类型
		return fmt.Errorf("路径 %s 中第 %d 个部分处不是map类型: %T", path, i, current)
	}

	return nil
}

// DecryptResponse 解密响应
func (s *DefaultCryptoService) DecryptResponse(response interface{}, headers map[string]string) error {
	// 如果未启用自动解密，则直接返回
	if !s.config.AutoDecrypt {
		return nil
	}

	// 检查是否需要解密
	cryptoAlg := headers["x-jlpay-crypto-alg"]
	if cryptoAlg == "" {
		// 尝试大写版本
		cryptoAlg = headers["X-Jlpay-Crypto-Alg"]
	}
	if cryptoAlg == "" {
		// 没有加密，无需解密
		return nil
	}

	// 检查加密算法是否支持
	if cryptoAlg != "SM2WithSM4" {
		return fmt.Errorf("不支持的加密算法: %s", cryptoAlg)
	}

	// 获取加密密钥
	encryptedKeyBase64 := headers["x-jlpay-key"]
	if encryptedKeyBase64 == "" {
		// 尝试大写版本
		encryptedKeyBase64 = headers["X-Jlpay-Key"]
	}
	if encryptedKeyBase64 == "" {
		return nil // 没有加密密钥，可能是标记请求但未实际加密
	}

	// 将Base64编码的密钥转为字节数组
	encryptedKey, err := utils.FromBase64String(encryptedKeyBase64)
	if err != nil {
		return fmt.Errorf("解码加密密钥失败: %w", err)
	}

	// 使用SM2解密SM4密钥
	sm4KeyBytes, err := utils.SM2Decrypt(encryptedKey, s.config.PrivateKey)
	if err != nil {
		return fmt.Errorf("SM2解密SM4密钥失败: %w", err)
	}

	// 搜集响应中的加密字段
	encryptedFields := make(map[string]string)
	for key, value := range headers {
		if strings.HasPrefix(key, "x-jlpay-encrypt-") {
			fieldPath := strings.Replace(key[15:], "-", ".", -1) // 去掉前缀，恢复字段路径
			encryptedFields[fieldPath] = value
		}
	}

	// 解密响应数据
	if len(encryptedFields) > 0 {
		err = s.decryptResponseData(response, encryptedFields, sm4KeyBytes)
		if err != nil {
			return fmt.Errorf("解密响应数据失败: %w", err)
		}
	}

	// 如果响应对象实现了SensitiveFieldsGetter接口，尝试解密敏感字段
	if sensitiveGetter, ok := response.(SensitiveFieldsGetter); ok {
		sensitiveFields := sensitiveGetter.GetSensitiveFields()
		if len(sensitiveFields) > 0 {
			err = s.decryptSensitiveFields(response, sensitiveFields, sm4KeyBytes)
			if err != nil {
				return fmt.Errorf("解密敏感字段失败: %w", err)
			}
		}
	}

	return nil
}

// encryptSensitiveData 对敏感字段进行加密
func (s *DefaultCryptoService) encryptSensitiveData(request interface{}, sensitiveFields []string, sm4Key []byte) (map[string]string, error) {
	result := make(map[string]string)

	// 处理原始请求Map的情况
	if rawMapGetter, ok := request.(RawMapGetter); ok {
		if rawMap, exist := rawMapGetter.GetRawMap(); exist && len(rawMap) > 0 {
			// 对原始请求Map中的敏感字段进行加密
			for _, fieldPath := range sensitiveFields {
				value, err := getNestedMapValue(rawMap, fieldPath)
				if err != nil {
					continue // 字段不存在或为nil，跳过
				}

				// 只加密非空字符串
				if strValue, ok := value.(string); ok && strValue != "" {
					encryptedValue, err := s.encryptFieldValue(strValue, sm4Key)
					if err != nil {
						return nil, fmt.Errorf("加密字段 %s 失败: %w", fieldPath, err)
					}
					result[fieldPath] = encryptedValue
				}
			}
			return result, nil
		}
	}

	// 处理结构体的情况
	for _, fieldPath := range sensitiveFields {
		fieldValue, err := getNestedFieldValue(request, fieldPath)
		if err != nil {
			continue // 字段不存在或为nil，跳过
		}

		// 只加密非空字符串
		if fieldValue.Kind() == reflect.String && fieldValue.String() != "" {
			encryptedValue, err := s.encryptFieldValue(fieldValue.String(), sm4Key)
			if err != nil {
				return nil, fmt.Errorf("加密字段 %s 失败: %w", fieldPath, err)
			}
			result[fieldPath] = encryptedValue
		}
	}

	return result, nil
}

// decryptSensitiveFields 解密敏感字段
func (s *DefaultCryptoService) decryptSensitiveFields(response interface{}, sensitiveFields []string, sm4Key []byte) error {
	// 1. 优先直接通过反射设置结构体字段
	for _, fieldName := range sensitiveFields {
		// 先尝试通过反射获取字段
		fieldValue, err := getNestedFieldValue(response, fieldName)
		if err == nil && fieldValue.Kind() == reflect.String && fieldValue.String() != "" {
			originalValue := fieldValue.String()

			decryptedValue, err := s.decryptFieldValue(originalValue, sm4Key)
			if err != nil {
				continue
			}
			// 通过反射设置解密后的值
			setFieldValue(response, fieldName, decryptedValue)
			continue
		} else {
		}

		// 如果反射失败，尝试从原始数据rawData中获取
		if rawDataGetter, ok := response.(interface {
			GetRawData() map[string]interface{}
		}); ok {
			responseData := rawDataGetter.GetRawData()
			if responseData != nil {
				if encryptedValue, exists := responseData[fieldName]; exists {
					if strValue, ok := encryptedValue.(string); ok && strValue != "" {
						decryptedValue, err := s.decryptFieldValue(strValue, sm4Key)
						if err != nil {
							continue
						}
						setFieldValue(response, fieldName, decryptedValue)
					} else {
					}
				} else {
				}
			} else {
			}
		} else {
		}
	}
	return nil
}

// decryptResponseData 解密响应数据
func (s *DefaultCryptoService) decryptResponseData(response interface{}, encryptedFields map[string]string, sm4Key []byte) error {
	for fieldPath, encryptedValue := range encryptedFields {
		// 解密字段值
		decryptedValue, err := s.decryptFieldValue(encryptedValue, sm4Key)
		if err != nil {
			return fmt.Errorf("解密字段 %s 失败: %w", fieldPath, err)
		}

		// 设置解密后的值到响应对象
		err = setNestedFieldValue(response, fieldPath, decryptedValue)
		if err != nil {
			// 字段不存在或不可设置，记录错误但继续处理其他字段
			utils.Debugf("设置解密字段 %s 失败: %v", fieldPath, err)
		}
	}
	return nil
}

// getNestedFieldValue 获取嵌套结构中的字段值
func getNestedFieldValue(obj interface{}, fieldPath string) (reflect.Value, error) {
	value := reflect.ValueOf(obj)
	if value.Kind() == reflect.Ptr {
		if value.IsNil() {
			return reflect.Value{}, fmt.Errorf("对象是空指针")
		}
		value = value.Elem()
	}

	fields := strings.Split(fieldPath, ".")
	for i, field := range fields {
		if value.Kind() != reflect.Struct {
			return reflect.Value{}, fmt.Errorf("路径 %s 的字段 %s 不是结构体",
				strings.Join(fields[:i], "."), field)
		}

		fieldValue := value.FieldByName(field)
		if !fieldValue.IsValid() {
			return reflect.Value{}, fmt.Errorf("字段 %s 不存在于路径 %s",
				field, strings.Join(fields[:i], "."))
		}

		// 处理指针类型
		if fieldValue.Kind() == reflect.Ptr {
			if fieldValue.IsNil() {
				return reflect.Value{}, fmt.Errorf("字段 %s 是空指针",
					strings.Join(fields[:i+1], "."))
			}
			fieldValue = fieldValue.Elem()
		}

		// 最后一个字段直接返回
		if i == len(fields)-1 {
			return fieldValue, nil
		}

		value = fieldValue
	}

	return value, nil
}

// setNestedFieldValue 设置嵌套结构中的字段值
func setNestedFieldValue(obj interface{}, fieldPath string, value string) error {
	target, err := getNestedFieldValue(obj, fieldPath)
	if err != nil {
		return err
	}

	if !target.CanSet() {
		return fmt.Errorf("字段 %s 不可写", fieldPath)
	}

	if target.Kind() != reflect.String {
		return fmt.Errorf("字段 %s 不是字符串类型", fieldPath)
	}

	target.SetString(value)
	return nil
}

// getNestedMapValue 从嵌套的map中获取值
func getNestedMapValue(data map[string]interface{}, path string) (interface{}, error) {
	parts := strings.Split(path, ".")
	var current interface{} = data

	// 遍历路径中的每个部分
	for i, part := range parts {
		// 尝试转换为map[string]interface{}
		if currentMapInterface, ok := current.(map[string]interface{}); ok {
			// 获取当前部分的值
			next, exists := currentMapInterface[part]
			if !exists {
				return nil, fmt.Errorf("路径 %s 中的 %s 不存在于map[string]interface{}中", path, part)
			}

			// 最后一个部分直接返回值
			if i == len(parts)-1 {
				return next, nil
			}

			// 否则继续向下遍历
			current = next
			continue
		}

		// 尝试转换为map[string]string
		if currentMapString, ok := current.(map[string]string); ok {
			// 获取当前部分的值
			next, exists := currentMapString[part]
			if !exists {
				return nil, fmt.Errorf("路径 %s 中的 %s 不存在于map[string]string中", path, part)
			}

			// 最后一个部分直接返回值
			if i == len(parts)-1 {
				return next, nil
			}

			// map[string]string不能再向下遍历，报错
			return nil, fmt.Errorf("路径 %s 中的 %s 处是map[string]string，无法继续向下访问", path, part)
		}

		// 都不是map类型
		return nil, fmt.Errorf("路径 %s 中的 %s 处，当前值不是map，类型为: %T", path, part, current)
	}

	return nil, fmt.Errorf("无效的路径: %s", path)
}

// getMapStringKeys 获取map[string]string的所有键，用于调试
func getMapStringKeys(m map[string]string) []string {
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	return keys
}

// encryptFieldValue 加密字段值
func (s *DefaultCryptoService) encryptFieldValue(value string, sm4Key []byte) (string, error) {
	if value == "" {
		return "", nil
	}

	// 使用SM4-ECB模式加密
	encryptedBytes, err := utils.SM4ECBEncrypt([]byte(value), sm4Key)
	if err != nil {
		return "", fmt.Errorf("SM4加密失败: %w", err)
	}

	// 将加密结果转为Base64字符串
	return utils.ToBase64String(encryptedBytes), nil
}

// decryptFieldValue 解密字段值
func (s *DefaultCryptoService) decryptFieldValue(value string, sm4Key []byte) (string, error) {
	if value == "" {
		return "", nil
	}

	// 将Base64字符串转为字节数组
	encryptedBytes, err := utils.FromBase64String(value)
	if err != nil {
		return "", fmt.Errorf("解码Base64字符串失败: %w", err)
	}

	// 使用SM4-ECB模式解密
	// 注意：sm4Key已经是原始字节，直接使用
	decryptedBytes, err := utils.SM4ECBDecrypt(encryptedBytes, sm4Key)
	if err != nil {
		return "", fmt.Errorf("SM4解密失败: %w", err)
	}

	result := string(decryptedBytes)
	return result, nil
}

// getFieldValue 获取字段值
func getFieldValue(obj interface{}, fieldPath string) (reflect.Value, error) {
	value := reflect.ValueOf(obj)
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}

	fields := strings.Split(fieldPath, ".")
	for _, field := range fields {
		if value.Kind() != reflect.Struct {
			return reflect.Value{}, fmt.Errorf("字段 %s 不是结构体", field)
		}

		value = value.FieldByName(field)
		if !value.IsValid() {
			return reflect.Value{}, fmt.Errorf("字段 %s 不存在", field)
		}

		if value.Kind() == reflect.Ptr {
			if value.IsNil() {
				return reflect.Value{}, fmt.Errorf("字段 %s 是空指针", field)
			}
			value = value.Elem()
		}
	}

	return value, nil
}

// setFieldValue 设置字段值
func setFieldValue(obj interface{}, fieldPath string, value string) error {
	val, err := getFieldValue(obj, fieldPath)
	if err != nil {
		return err
	}

	if !val.CanSet() {
		return fmt.Errorf("字段 %s 不可写", fieldPath)
	}

	if val.Kind() != reflect.String {
		return fmt.Errorf("字段 %s 不是字符串类型", fieldPath)
	}

	val.SetString(value)
	return nil
}
